#pragma once

#include <iostream>
#include <string>

#include <cstring>
#include <cstdlib>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/wait.h>
#include <pthread.h>

#include "log.hpp"
#include "Task.hpp"
#define __TEST__
#include "thread_pool.hpp"
#include "Daemon.hpp"

extern Log log;

constexpr int default_listen_sockfd = -1;
constexpr uint16_t default_port = 8080;
const std::string default_ip = "0.0.0.0";
constexpr int backlog = 5;

// class thread_data
// {
// public:
//     thread_data(int sockfd, const std::string& ip, uint16_t port)
//         : _sockfd(sockfd)
//         , _ip(ip)
//         , _port(port)
//     {}

//     int _sockfd;
//     std::string _ip;
//     uint16_t _port;
// };
// void* Routine(void* args)
// {
//     const thread_data* td = static_cast<const thread_data*>(args);
//     pthread_detach(pthread_self());
//     Service(td->_sockfd, td->_ip, td->_port);
//     delete td;
//     close(td->_sockfd);
//     return nullptr;
// }

template<class T>
class TCPServer
{
    typedef T value_type;
public:
    enum TCPServer_Error
    {
        SOCKET_CREATE_ERROR = 1,
        SOCKET_BIND_ERROR,
        SOCKET_LISTEN_ERROR,
        SOCKET_ACCEPT_ERROR
    };

    TCPServer(uint16_t port = default_port, std::string ip = default_ip)
        : _listen_sockfd(default_listen_sockfd)
        , _ip(ip)
        , _port(port)
    {}
    
    void server_init()
    {
        log.change_method(Class);
        Daemon();
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_sockfd < 0)
        {
            log(Fatal, "socket create error, listen_sockfd: %d, errno: %d, errstring: %s", _listen_sockfd, errno, strerror(errno));
            exit(SOCKET_CREATE_ERROR);
        }
        log(Info, "socket create success, listen_sockfd = %d", _listen_sockfd);
        
        int opt = 1;
        setsockopt(_listen_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); //配置套接字,防止偶发性服务器无法立即重启

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(), &(local.sin_addr));
        // local.sin_addr.s_addr = inet_addr(_ip.c_str());
        
        if (bind(_listen_sockfd, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            log(Fatal, "socket bind error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_BIND_ERROR);
        }
        log(Info, "socket bind success");

        if (listen(_listen_sockfd, backlog) < 0)
        {
            log(Fatal, "socket listen error, errno: %d, errstring: %s", errno, strerror(errno));
            exit(SOCKET_LISTEN_ERROR);
        }
        log(Info, "socket listen success");
        
        _thread_pool.start();
    }

    void start()
    {
        log(Info, "TCPserver is running");
        while (true)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listen_sockfd, (struct sockaddr*)&client, &len);
            if (sockfd < 0)
            {
                log(Warning, "socket accept error, errno: %d, errstring: %s", errno, strerror(errno));
                continue;
            }
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &client.sin_addr, clientip, INET_ADDRSTRLEN - 1);
            
            log(Info, "get a new link..., sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip, clientport);
            
            // 单执行流
            // Service(sockfd, clientip, clientport);
            // close(sockfd);
            
            // 多进程
            // pid_t id = fork();
            // if (id == 0)
            // {
            //     close(_listen_sockfd);
            //     if (fork() > 0)
            //         exit(0);
            //     Service(sockfd, clientip, clientport);
            //     close(sockfd);
            //     exit(0); 
            // }
            // close(sockfd);
            // pid_t rid = waitpid(id, nullptr, 0);
            // (void)rid;

            // 多线程
            // thread_data* td = new thread_data(sockfd, clientip, clientport);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, td);

            // 线程池
            Task<> t(sockfd, clientip, clientport);
            _thread_pool.push(std::move(t));
        }
    }

    ~TCPServer()
    {
        if (_listen_sockfd > 0)
            close(_listen_sockfd);
    }
private:
    int _listen_sockfd; //监听网络资源文件描述符套接字
    std::string _ip;
    uint16_t _port;
    ThreadPool<value_type> _thread_pool;
};